

/******************************************************************************
 *
 *
 * File:	USB_GUI_0100_M52259DEMO.c
 *
 *
 ******************************************************************************/

/*****************************************************************************
 *
 *
 * This is a demonstration program showing USB communications using
 *		usb_logger.c. For a description of its operation see
 *		USB_GUI_0100 rev100.doc.
 *
 *
 *****************************************************************************/



#include <mqx.h>
#include <bsp.h>
#include "main.h"
#include <usb_logger.h>
#include <USB_GUI_0100_M52259DEMO.h>

// Constants
static const char START_BYTE = 0x02;
static const char END_BYTE = 0x03;

// Size of incoming buffer in samples.
static const INCOMING_BUFFER_SIZE = 500;

// Size of the outgoing buffer in samples
static const OUTGOING_BUFFER_SIZE = 500;

// Number of characters needed to represent the sample number.
static const SAMPLE_NUM_CHAR_SIZE = 8;

// Number of characters needed to represent shaker data.
static const SHAKER_CHAR_SIZE =4;

// Number of characters needed to represent an ADC reading.
static const ADC_CHAR_SIZE = 3;

// List of possible data transfer commands.
enum CommandType 
{
	START = 0x01,
	STOP = 0x02,
	RESET = 0x03,
	PC_DATA = 0x04,
	BOARD_DATA = 0x05,
	BOARD_READY = 0x06,
	BOARD_NOT_READY = 0x07,
	RESEND_SAMPLE = 0x08
};

// Data structure for 
typedef struct { 
	char sampleNum[SAMPLE_NUM_CHAR_SIZE];
	char shaker1Data[SHAKER_CHAR_SIZE];
	char shaker2Data[SHAKER_CHAR_SIZE]; 
} SampleData;


// Data structure for ADC samples.
typedef struct 
{
	char accelerometer1[ADC_CHAR_SIZE];
	char accelerometer2[ADC_CHAR_SIZE];
	char accelerometer3[ADC_CHAR_SIZE];
} AdcData;

// Structure for incoming circular buffer.
typedef struct {
    int size;		// Size of buffer in samples
    int reader;   	// Reader pointer position
    int writer;		// Writer pointer position
    long readCount;	// Total number of reads performed
    long writeCount;	// Total number of writes performed
    SampleData   *sample;	// Struct containing shaker sample data
    AdcData *response;	// Struct containing sample response data
} CircularBuffer;
 

/** 
* Variable Declarations
*/

CircularBuffer inBuffer;
CircularBuffer outBuffer;

SampleData tempSampleData;
AdcData tempAdcData;

// Reference external USB endpoints.
extern EP_RX_CTRL ep1_rx_ctrl;
extern EP_RX_CTRL ep3_rx_ctrl;

/* Logger Global Variable Structure. */
extern LOGGER_GLOBAL_VARIABLE_STRUCT g_logger;


/* Handles for operating the LEDs LED(1:2),SW(1:2) and ADCs. */
/* Ref: Freescale MQX I/O Drivers Users Guide (MQXIOUG.pdf). Chapter 7 */

FILE_PTR led_file1, led_file2, led_file3, sw_file, result_file;

/*
 *	Arrays for operating the LEDs and switches.
 */

/* LED Arrays */

/* Declare arrays of type 
       GPIO_PIN_STRUCT (...\lib\m52259demo.cw\mqx\io_gpio.h) 
               which define the LED pins in the format 
               <port_name> | <pin_number> | <additional_flage>.
       Ref: MQX I/O User's Guide "7.5 Opening GPIO Device"
 */

/* Define an array listing all the LEDs. It will be used to open
               a GPIO device driver for controlling the LEDs. */
GPIO_PIN_STRUCT pins1[] ={
    /* Open file to control LEDs(1:4) and initialise their status to OFF.
            Here <additional_flags> = GPIO_PIN_STATUS_0 will clear the pin. */
    BSP_LED1 | GPIO_PIN_STATUS_0, // 
    BSP_LED2 | GPIO_PIN_STATUS_0,
    BSP_LED3 | GPIO_PIN_STATUS_0,
    BSP_LED4 | GPIO_PIN_STATUS_0,
    GPIO_LIST_END
};

/* Define arrays for writing to the LEDs individually.
       These are used with the Generic IOCTL Commands. */

/* For controlling LED1 individually */
GPIO_PIN_STRUCT pins2[] ={
    BSP_LED1,
    GPIO_LIST_END
};

/* For controlling LED2 individually */
GPIO_PIN_STRUCT pins3[] ={
    BSP_LED2,
    GPIO_LIST_END
};

/* For controlling LED3 individually */
GPIO_PIN_STRUCT pins4[] ={
    BSP_LED3,
    GPIO_LIST_END
};

/* For controlling LED4 individually */
GPIO_PIN_STRUCT pins5[] ={
    BSP_LED4,
    GPIO_LIST_END
};


/* Define an array listing all the Switches. It will be used to open
               a GPIO device driver for controlling the Switches. */
GPIO_PIN_STRUCT pins6[] ={
    BSP_BUTTON1 | GPIO_PIN_IRQ_FALLING, // Interrupt on falling edge
    BSP_BUTTON2 | GPIO_PIN_IRQ_FALLING,
    GPIO_LIST_END
};


  
/*****************************************************************************
 *  
 *   @name        TestApp_Init
 * 
 *   @brief       This function is the entry for USB Logger (or other usuage)
 * 
 *   @param       None
 * 
 *   @return      None
 *              
 *****************************************************************************/
 
void TestApp_Init(void) {

    USB_Class_LOGGER_Init();
    
    initialiseBuffer(&inBuffer, INCOMING_BUFFER_SIZE, 0);
    initialiseBuffer(&outBuffer, OUTGOING_BUFFER_SIZE, 1);

    /* Initialise the endpoint control structure */
    Endpoint_Init();

    /* Initialise control of LED(1:2) */
    LED_1_4_Init();

    while (TRUE) {
        /* Check for the arrival of a packet at EP1 or EP3 */
        EP1_3_PACKET_REC();

        /* Repeat every 100mSec. */
        _time_delay(100);
    }

}



/****************************************************************************
 *
 * Function Name  : Endpoint_Init
 * Returned Value : None
 *
 * Operation	  : Initialises the structures for controlling 
 *                   endpoint transactions.
 *					Structures store data packets received at OUT endpoints.
 *
 ***************************************************************************/
void Endpoint_Init(void) {

    EP_RX_CTRL_PTR epctrlPtr; // Pointer to an EP control structure

    /* Initialise EP1 structure */
    epctrlPtr = &ep1_rx_ctrl; // Set the pointer to the EP1 control structure
    epctrlPtr->pkt_rec = FALSE; // Clear packet received flag
    epctrlPtr->overrun_err = FALSE; // Clear overrun error flag
    epctrlPtr->len = 0x00; // Received packet length zero

    /* Initialise EP3 structure */
    epctrlPtr = &ep3_rx_ctrl; // Set the pointer to the EP3 control structure
    epctrlPtr->pkt_rec = FALSE; // Clear packet received flag
    epctrlPtr->overrun_err = FALSE; // Clear overrun error flag
    epctrlPtr->len = 0x00; // Received packet length zero


}

/****************************************************************************
 *
 * Function Name  : LED_1_4_Init
 * Returned Value : None
 *
 *	Operation:		Open a GPIO device for writing to the LEDs.
 *					Specify the pins to be used (BSP_LED1:BSP_LED4)
 *						and the pin direction (OUT - write).
 *					Open a GPIO device for reading the switches SW1 & SW2.
 *					Specify the pins to be used (BSP_BUTTON1, BSP_BUTTON2)
 *						and the pin direction (IN - read).
 * 					Each open operation returns a handle to the GPIO device.
 *
 ***************************************************************************/

void LED_1_4_Init() {
    /* Open a GPIO device for writing to the LEDs */
    led_file1 = fopen("gpio:write", (char_ptr) & pins1);

    /* Open a GPIO device for reading the switches. */
    sw_file = fopen("gpio:read", (char_ptr) & pins6);

    /* Switches are programmed to generate an interrupt off the falling edge
            when they are pressed */
    /* Specify <handle>, <operation>, <interrupt service routine> */
    ioctl(sw_file, GPIO_IOCTL_SET_IRQ_FUNCTION, Switch_Read);
    ioctl(sw_file, GPIO_IOCTL_ENABLE_IRQ, NULL); // Enable the interrupt.

}

/****************************************************************************
 *
 * Function Name  : Switch_Read
 * Returned Value : None
 *
 * Operation	  : Callback function called as an interrupt service routine 
 *                   when a switch is pressed.
 *					Determines which switch was pressed (SW1 or SW2) and
 *						Sends the information to the host.
 *
 ***************************************************************************/

void Switch_Read(void) {
    // 	uint_8 sw_status;

    /* Determine which switch has been pressed and send the information to 
            the Host */
    ioctl(sw_file, GPIO_IOCTL_READ, &pins6); // Read the switch status.
    if ((pins6[0] & GPIO_PIN_STATUS) == GPIO_PIN_STATUS_1) // SW2 pressed?
    {

        // Switch 2 has been pressed. Send a string less or equal to 64 characters.
        char outputMessage[] = "Get fucked world";
        int i = 0;
        
        while (outputMessage[i] != '\0' && i < PC_BUFFER_SIZE) {
            g_logger.rpt_buf[i] = outputMessage[i];
            i++;
        }
        (void) USB_Class_EP2_Send_Data(USB_EP2, g_logger.rpt_buf, PC_BUFFER_SIZE);
    }
    
    // Switch 1 Pressed
    if ((pins6[1] & GPIO_PIN_STATUS) == GPIO_PIN_STATUS_1)
    {
        g_logger.rpt_buf[0] = 1; // Yes! SW1 pressed. Send data to host.
        (void) USB_Class_EP2_Send_Data(USB_EP2, g_logger.rpt_buf, PC_BUFFER_SIZE);

    }
}


/****************************************************************************
 *
 * Function Name  : EP1_3_PACKET_REC()
 * Returned Value : None
 *
 * Operation	  : Checks for the arrival of a packet at EPn where n(1,3)
 *						and processes received packets.
 *					The  structures ep1_rx_ctrl and ep3_rx_ctrl (declared in
 *						usb_logger.c) are used for controlling packet
 *						reception.
 *					The arrival of a packet is indicated 
 *						by the flag epn_rx_ctrl.pkt_rec.
 *					Received packets are transferred to the 
 *						receive packet buffer epn_rx_ctrl.ep_pkt_buf[].
 *					The size of a received packet is indicated by
 *						epn_rx_ctrl.len.
 *                   
 *
 ***************************************************************************/
void EP1_3_PACKET_REC(void) {
    uint_8 count, command;
    uint_32 byte_count; // 
    EP_RX_CTRL_PTR ep1ctrlPtr; // Pointer for an EP1 control structure
    EP_RX_CTRL_PTR ep3ctrlPtr; // Pointer for an EP3 control structure

    /*  */
    ep1ctrlPtr = &ep1_rx_ctrl; // Set the pointer to the EP1 control structure
    ep3ctrlPtr = &ep3_rx_ctrl; // Set the pointer to the EP3 control structure

    /* Check for an EP1 received packet */
    if (ep1ctrlPtr->pkt_rec == TRUE) {
        /* EP1 packet has arrived */
        /* Transfer the packet to the EP1 receive packet buffer ep_pht_buf[]. */
        byte_count = ep1ctrlPtr->len; // Packet size
        for (count = 0; count < ep1ctrlPtr->len; count++) {
            ep1ctrlPtr->ep_pkt_buf[count] = *ep1ctrlPtr->buffer_ptr++;
        }

        /* Clear packet received flag */
        ep1ctrlPtr->pkt_rec = FALSE;

        /* Check for an overrun error */
        if (ep1ctrlPtr->overrun_err == TRUE) {
            /* Ignore for now. */
            ep1ctrlPtr->overrun_err = FALSE;
        }

        /* Process the EP1 command: EP1 controls LED(1:2) */
        command = ep1ctrlPtr->ep_pkt_buf[0]; // Command is the first byte in the buffer
        switch (command) {
            case LEDS_OFF: // both LEDs off
                ioctl(led_file1, GPIO_IOCTL_WRITE_LOG0, &pins1);
                break;

            case LED1_ON: // LED1 on
                ioctl(led_file1, GPIO_IOCTL_WRITE_LOG1, &pins2);
                break;

            case LED2_ON: // LED2 on
                ioctl(led_file1, GPIO_IOCTL_WRITE_LOG1, &pins3);
                break;

        }
    }


    /* Check for an EP3 received packet */
    if (ep3ctrlPtr->pkt_rec == TRUE) {
        /* EP3 packet has arrived */
        /* Transfer the packet to the EP3 receive packet buffer ep_pht_buf[]. */
        byte_count = ep3ctrlPtr->len; // Packet size
        for (count = 0; count < ep3ctrlPtr->len; count++) {
            ep3ctrlPtr->ep_pkt_buf[count] = *ep3ctrlPtr->buffer_ptr++;
        }

        /* Clear packet received flag */
        ep3ctrlPtr->pkt_rec = FALSE;

        /* Check for an overrun error */
        if (ep3ctrlPtr->overrun_err == TRUE) {
            /* Ignore for now. */
            ep3ctrlPtr->overrun_err = FALSE;
        }

        /* Process the EP3 command: EP3 controls LED4*/
        command = ep3ctrlPtr->ep_pkt_buf[0]; // Command is the first byte in the buffer
        switch (command) {
            case WRITE_LEDS: // Write data to LED4
                switch (ep3ctrlPtr->ep_pkt_buf[1]) {
                    case LED4_ON: // LED4 On
                        ioctl(led_file1, GPIO_IOCTL_WRITE_LOG1, &pins5);
                        break;

                    case LED4_OFF: // LED4 Off
                        ioctl(led_file1, GPIO_IOCTL_WRITE_LOG0, &pins5);
                        break;
                }
                break;
        }
    }
}

/** initialiseBuffer **********
*
* Initialise the circular buffer for incoming messages.
*
* @param cb				The circular buffer to be initialised.
* @param size			The maximum number of samples the buffer can contain.
* @param isOutputBuffer True if the buffer should contain output adc data fields.
*/
void initialiseBuffer(CircularBuffer* cb, int size, int isOutputBuffer)
{
	cb->size = size;
	cb->reader = 0;
	cb->writer = 0;
	
	// Allocate the memory needed to store the shaker data.
//	cb->data = (SampleData *)calloc(cb->size, sizeof(SampleData));
	
	// Allocate the memory needed to store ADC data if the buffer is used for output.
	if (isOutputBuffer == 1)
	{
//		cb->sample = (AdcData *)calloc(cb->size, sizeof(AdcData));
	}
}

/** readSampleFromBuffer **********
*
* Read the sample data from the current position in the buffer.
*
* @param cb	Circular buffer to be read from.
* @param sample	Sample data structure to store the buffer information.
*/
void readSampleFromBuffer(CircularBuffer *cb, SampleData *sample)
{
	*sample = cb->sample[cb->reader];
}


/** writeSampleToBuffer **********
*
* Write sample data to the current position in the buffer.
*
* @param cb	Circular buffer to write to.
* @param sample	Sample data to be written.
*/
void writeSampleToBuffer(CircularBuffer *cb, SampleData *sample)
{
	cb->sample[cb->writer] = *sample;
}


/** writeResponseToBuffer **********
*
* Write sample data response to the current position in the buffer.
*
* @param cb	Circular buffer to write to.
* @param response	Response data to be written.
*/
void writeResponseToBuffer(CircularBuffer *cb, AdcData *response)
{
	cb->response[cb->writer] = *response;
}


/** incrementReader **********
*
* Increment the reader position in the buffer.
* The reader should never overtake the writer.
*
* @param cb Circular buffer that the reader belongs to.
*/
void incrementReader(CircularBuffer *cb)
{
	// Do not allow the reader to overtake the writer.
	if (cb->readCount < cb->writeCount)
	{
		// Reset the read pointer if it has reached the end of the buffer.
		if (cb->reader == cb->size)
		{
			cb->reader =0;
		}
		else
		{
			cb->reader++;
		}
		
	cb->readCount++;
	}
}


/** incrementWriter **********
*
* Increment the reader position in the buffer.
* The writer should never overtake the reader.
*
* @param cb Circular buffer that the reader belongs to.
*/
void incrementWriter(CircularBuffer *cb)
{
	// Do not allow the writer to overtake the reader.
	if (cb->writeCount < (cb->readCount + cb->size))
	{
		if (cb->writer == cb->size)
		{
			cb->writer == 0;
		}
		else
		{
			cb->writer++;
		}
		
	cb->writeCount++;
	}
}

// isBufferLow
// isBufferHigh



